package com.miyake.loveviewweb.client;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.google.appengine.api.datastore.Key;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.miyake.loveviewweb.client.service.DataService;
import com.miyake.loveviewweb.client.service.DataServiceAsync;
import com.miyake.loveviewweb.shared.model.ChartModel;
import com.miyake.loveviewweb.shared.model.DataModel;
import com.miyake.loveviewweb.shared.model.FolderModel;
import com.miyake.loveviewweb.shared.model.ValueModel;
import com.miyake.loveviewweb.shared.model.ChartModel.ChartEngine;

public class DataServiceWrapper {
    public ChartModel getSelectedChart() {
        return selectedChart;
    }

    public FolderModel getSelectedFolder() {
        return selectedFolder;
    }

    public DataModel getSelectedData() {
        return selectedData;
    }

    private static DataServiceWrapper instance;;
    private static List<DataServiceListener> listeners = new ArrayList<DataServiceListener>();
    private static DataServiceAsync service = DataService.Util.getInstance();
    private FolderModel selectedFolder;
    private DataModel selectedData;
    private Key selectedKey;
    protected ChartModel selectedChart;
    
    private DataServiceWrapper() {
        
    }
    
    public static DataServiceWrapper getInstance() {
        if (instance == null) {
            instance = new DataServiceWrapper();
            service.getRootFolders(new AsyncCallback<List<FolderModel>>() {
                public void onFailure(Throwable caught) {
                    Window.alert(caught.getMessage());
                }

                public void onSuccess(List<FolderModel> result) {
                    if (result.size() > 0) {
                        instance.selectedFolder = result.get(0);
                    }
                }    
            });
        }
        return instance;
    }
    public void addDataServiceListener(DataServiceListener listener) {
        listeners.add(listener);
    }
    
    protected void fireCreateRootFolderEvent(FolderModel folder) {
        for (DataServiceListener listener : listeners) {
            listener.onCreateRootFolder(folder);
        }
    }
    
    protected void fireCreateFolderEvent(FolderModel folder, FolderModel parent) {
        for (DataServiceListener listener : listeners) {
            listener.onCreateFolder(folder, parent);
        }
    }
    
    protected void fireCreateDataEvent(DataModel data, FolderModel parent) {
        for (DataServiceListener listener : listeners) {
            listener.onCreateData(data, parent);
        }
    }

    protected void fireSelectChangeEvent(Object object, FolderModel parent) {
        for (DataServiceListener listener : listeners) {
            listener.onSelectChange(object, parent);
        }
    }
    
    protected void fireCreateChartEvent(ChartModel chart,
            DataModel parent) {
        for (DataServiceListener listener : listeners) {
            listener.onCreateChart(chart, parent);
        }
    }
    
    protected void fireDeleteEvent(Key key) {
        for (DataServiceListener listener : listeners) {
            listener.onDelete(key);
        }     
    }
    
    protected void fireDataUpdateEvent(Key data) {
        for (DataServiceListener listener : listeners) {
            listener.onUpdateData(data);
        }   
    }
    
    protected void fireFolderUpdateEvent(Key key) {
        for (DataServiceListener listener : listeners) {
            listener.onUpdatFolder(key);
        }    
    }
    
    public FolderModel createRootFolder(String name) {
        service.createRootFolder(name, new AsyncCallback<FolderModel>() {

            public void onFailure(Throwable caught) {
                Window.alert(caught.getMessage());
            }

            public void onSuccess(FolderModel result) {
                fireCreateRootFolderEvent(result);
            }
            
        });
        return null;
    }
    
    public FolderModel createFolder(String name, Key parentFolderKey) {
        service.createFolder(name, parentFolderKey, new AsyncCallback<FolderModel>() {

            public void onFailure(Throwable caught) {
                Window.alert(caught.getMessage()); 
            }

            public void onSuccess(FolderModel result) {
                fireCreateFolderEvent(result, selectedFolder);
            }
            
        });
        
        return null;
    }
    
    public void createData(String name, String text, Key parentFolderKey) {
        service.createData(parentFolderKey, name, text, new AsyncCallback<DataModel>() {

            public void onFailure(Throwable caught) {
                Window.alert(caught.getMessage());
            }

            public void onSuccess(DataModel result) {
                fireCreateDataEvent(result, selectedFolder);
            }
            
        });
    }
    
    public ChartModel createChart(String name, Key parentDataKey, Map<String, String> axes, ChartEngine chartEngine, Key pluginKey) {
        service.createChart(name, parentDataKey, axes, chartEngine, pluginKey, new AsyncCallback<ChartModel>() {

            public void onFailure(Throwable caught) {
                Window.alert(caught.getMessage()); 
            }

            public void onSuccess(ChartModel result) {
                fireCreateChartEvent(result, selectedData); 
            }
            
        });
        return null;
    }


    public void setSelectedItem(Key key) {
        service.setSelectedItem(key, new AsyncCallback<Void>() {
            public void onFailure(Throwable caught) {  
            }

            public void onSuccess(Void result) {
            }            
        });
        
        selectedKey = key;
        
        if (FolderModel.class.getName().contains(key.getKind())) {
            selectedData = null;
            service.getFolder(key, new AsyncCallback<FolderModel>() {

                public void onFailure(Throwable caught) {
                    // TODO Auto-generated method stub
                    
                }

                public void onSuccess(FolderModel result) {
                    selectedFolder = result;  
                    fireSelectChangeEvent(selectedFolder, selectedFolder);
                }
                
            });
        }
        else if (DataModel.class.getName().contains(key.getKind())) {
            service.getData(key, false, new AsyncCallback<DataModel>() {

                public void onFailure(Throwable caught) {
  
                }

                public void onSuccess(DataModel result) {
                    selectedData = result;
                    service.getFolder(selectedData.getFolder(), new AsyncCallback<FolderModel>() {
                        public void onFailure(Throwable caught) {
                        }

                        public void onSuccess(FolderModel result) {
                            selectedFolder = result;
                            fireSelectChangeEvent(selectedData, selectedFolder);
                        }
                    });
                }
                
            });
        }    
        else if (ChartModel.class.getName().contains(key.getKind())) {

            service.getChart(key, false, new AsyncCallback<ChartModel>() {

                public void onFailure(Throwable caught) {
                    // TODO Auto-generated method stub
                    
                }

                public void onSuccess(ChartModel result) {
                    selectedChart = result;
                    service.getData(selectedChart.getParentKey(), true, new AsyncCallback<DataModel>() {
                        public void onFailure(Throwable caught) {
                            Window.alert(caught.getMessage());
                        }

                        public void onSuccess(DataModel result) {
                            selectedData= result;
                            service.getFolder(selectedData.getFolder(), new AsyncCallback<FolderModel>() {
                                public void onFailure(Throwable caught) {
                                    Window.alert(caught.getMessage());
                                }

                                public void onSuccess(FolderModel result) {
                                    selectedFolder = result; 
                                    selectedKey = selectedChart.getKey();
                                    fireSelectChangeEvent(selectedChart, selectedFolder);  
                                }
                            });
                        }
                        
                    });  
                }
                
            });
        }
    }

    
    public void updateData(final DataModel data) {
        service.updateData(data, new AsyncCallback<Void>() {

            public void onFailure(Throwable caught) {
                Window.alert(caught.getMessage());
            }

            public void onSuccess(Void result) {
                fireDataUpdateEvent(data.getKey());
            }
            
        });
    }
    
    public void updateFolder(final FolderModel folder) {
        service.updateFolder(folder, new AsyncCallback<Void>() {
            public void onFailure(Throwable caught) {

            }

            public void onSuccess(Void result) {
                fireFolderUpdateEvent(folder.getKey());
            }  
        });
    }



    public DataServiceAsync getService() {
        return service;
    }

    public Key getSelectedKey() {
        return this.selectedKey;
    }

    public void delete(final Key selectedKey) {
        service.delete(selectedKey, new AsyncCallback<Void>() {

            public void onFailure(Throwable caught) {
                Window.alert(caught.getMessage());
            }

            public void onSuccess(Void result) {
                fireDeleteEvent(selectedKey);
            }
            
        });
    }

    public void delete(final List<Key> keys) {
        service.delete(keys, new AsyncCallback<Void>() {
            public void onFailure(Throwable caught) {
                Window.alert(caught.getMessage());
            }

            public void onSuccess(Void result) {
                for (Key key : keys) {
                    fireDeleteEvent(key);
                }
            }
        });
    }

    public void analyze(Key pluginKey, List<ValueModel> values, Map<String, String> data, final Key dataKey) {
        service.executeDataProcessing(pluginKey ,values, data, dataKey, new AsyncCallback<Key>() {
             public void onFailure(Throwable caught) {
             }

             public void onSuccess(Key result) {
                 fireDataUpdateEvent(dataKey);
             }
                 
        });   
    }

    public void parseFile(Key pluginKey, final Key dataKey) {
        service.parseFile(
            dataKey, pluginKey, new AsyncCallback<Void>() {
                public void onFailure(Throwable caught) {
                }

                public void onSuccess(Void result) {
                    fireDataUpdateEvent(dataKey);
                }
                
            }
        );
    }
}
